/**
 * Copyright (c) 2019 - 2020 IoT Company of Midea Group.
 *
 * File Name 	    : 
 * Description	    : rtos adaptor
 *
 * Version	        : v0.1
 * Author			: 
 * Date	            : 2019/09/15  refactoring
 * History	        : 
 */

#ifndef __MS_OSAL_LIST_H__
#define __MS_OSAL_LIST_H__

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Get offset of a member variable.
 *
 * @param[in]  type    the type of the struct this is embedded in.
 * @param[in]  member  the name of the variable within the struct.
 */
#define ms_offsetof(type, member) ((size_t)&(((type *)0)->member))

/**
 * @brief Get the struct for this entry.
 *
 * @param[in]  ptr     the list head to take the element from.
 * @param[in]  type    the type of the struct this is embedded in.
 * @param[in]  member  the name of the variable within the struct.
 */
#define ms_container_of(ptr, type, member) \
        ((type *)((char *)(ptr) - ms_offsetof(type, member)))

/** for single link list */
typedef struct slist_s {
    struct slist_s *next;
} slist_t;

static inline void slist_add(slist_t *node, slist_t *head)
{
    node->next = head->next;
    head->next = node;
}

static inline void slist_add_tail(slist_t *node, slist_t *head)
{
    while (head->next) {
        head = head->next;
    }

    slist_add(node, head);
}

static inline void slist_del(slist_t *node, slist_t *head)
{
    while (head->next) {
        if (head->next == node) {
            head->next = node->next;
            break;
        }

        head = head->next;
    }
}

static inline int slist_empty(const slist_t *head)
{
    return !head->next;
}

static inline void slist_init(slist_t *head)
{
    head->next = 0;
}

/**
* @brief Iterate over list of given type.
*
* @param[in]  queue   he head for your list.
* @param[in]  node    the type * to use as a loop cursor.
* @param[in]  type    the type of the struct this is embedded in.
* @param[in]  member  the name of the slist_t within the struct.
*/
#define slist_for_each_entry(queue, node, type, member)            \
        for (node = ms_container_of((queue)->next, type, member); \
            &node->member;                                         \
            node = ms_container_of(node->member.next, type, member))

/**
 * Iterate over list of given type safe against removal of list entry.
 *
 * @param[in]  queue   the head for your list.
 * @param[in]  tmp     the type * to use as a temp.
 * @param[in]  node    the type * to use as a loop cursor.
 * @param[in]  type    the type of the struct this is embedded in.
 * @param[in]  member  the name of the slist_t within the struct.
 */
#define slist_for_each_entry_safe(queue, tmp, node, type, member)  \
        for (node = ms_container_of((queue)->next, type, member), \
            tmp = (queue)->next ? (queue)->next->next : NULL;      \
            &node->member;                                         \
            node = ms_container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp)

/**
 * Initialise the list.
 *
 * @param[in]  name  the list to be initialized.
 */
#define MS_SLIST_HEAD_INIT(name) {0}

/**
 * @brief Initialise the list.
 *
 * @param[in]  name  the list to be initialized.
 */
#define MS_SLIST_HEAD(name) slist_t name = MS_SLIST_HEAD_INIT(name)

/**
 * @brief Get the struct for this entry.
 *
 * @param[in]  addr    the list head to take the element from.
 * @param[in]  type    the type of the struct this is embedded in.
 * @param[in]  member  the name of the slist_t within the struct.
 */
#define slist_entry(addr, type, member) \
        (addr ? (type *)((long)addr - ms_offsetof(type, member)) : (type *)addr)

/**
* @brief Get the first element from a list.
*
* @param[in]  ptr     the list head to take the element from.
* @param[in]  type    the type of the struct this is embedded in.
* @param[in]  member  the name of the slist_t within the struct.
*/
#define slist_first_entry(ptr, type, member) slist_entry((ptr)->next, type, member)

/**
 * @brief Get the list length.
 *
 * @param[in]  queue  the head for your list.
 */
static inline int slist_entry_number(slist_t *queue)
{
    int num;

    slist_t *cur = queue;

    for (num = 0; cur->next; cur = cur->next, num++)
        ;

    return num;
}


/** for single link list */
typedef struct ms_osal_slist_s {
    struct ms_osal_slist_s *next;
} ms_osal_slist_t;

static inline void ms_osal_slist_add(ms_osal_slist_t *node, ms_osal_slist_t *head)
{
   slist_add((slist_t*)node,(slist_t*)head);
}

static inline void ms_osal_slist_add_tail(ms_osal_slist_t *node, ms_osal_slist_t *head)
{
    slist_add_tail((slist_t*)node,(slist_t*)head);
}

static inline void ms_osal_slist_del(ms_osal_slist_t *node, ms_osal_slist_t *head)
{
    slist_del((slist_t*)node,(slist_t*)head);
}

static inline int ms_osal_slist_empty(const ms_osal_slist_t *head)
{
    return slist_empty((slist_t*)head);
}

static inline void ms_osal_slist_init(ms_osal_slist_t *head)
{
    slist_init((slist_t*)head);
}

static inline int ms_osal_slist_length_get(ms_osal_slist_t *head)
{
    return slist_entry_number((slist_t*)head);
}

/**
* @brief Iterate over list of given type.
*
* @param[in]  queue   he head for your list.
* @param[in]  node    the type * to use as a loop cursor.
* @param[in]  type    the type of the struct this is embedded in.
* @param[in]  member  the name of the slist_t within the struct.
*/
#define ms_osal_slist_for_each_entry(queue, node, type, member)  slist_for_each_entry(queue, node, type, member)

/**
 * @brief Iterate over list of given type safe against removal of list entry.
 *
 * @param[in]  queue   the head for your list.
 * @param[in]  tmp     the type * to use as a temp.
 * @param[in]  node    the type * to use as a loop cursor.
 * @param[in]  type    the type of the struct this is embedded in.
 * @param[in]  member  the name of the slist_t within the struct.
 */
#define ms_osal_slist_for_each_entry_safe(queue, tmp, node, type, member)  slist_for_each_entry_safe(queue, tmp, node, type, member)

#ifdef __cplusplus
}
#endif

#endif
